from scipy import integrate
import numpy as np


def romberg(f, start, end, show_latex=False):
    tolerance = 1e-7
    interval = end - start
    last_row = [(f(start) + f(end)) * interval / 2]
    if show_latex:
        print('$%0.3e$ \\\\\\hline' % abs(last_row[0] + 3 / (4 * np.pi)))

    for i in range(1, 100):
        points = np.linspace(start + interval * 2 ** (-i), end - interval * 2 ** (-i), num=2 ** (i - 1))
        row = [last_row[0] / 2 + np.sum(f(points)) * interval * 2 ** (-i)]
        for j in range(i):
            result = (4 ** (j + 1) * row[j] - last_row[j]) / (4 ** (j + 1) - 1)
            row.append(result)
        if show_latex:
            for k in range(len(row) - 1):
                print('$%0.3e$' % abs(row[k] + 3 / (4 * np.pi)), end=' & ')
            print('$%0.3e$ \\\\\\hline' % abs(row[-1] + 3 / (4 * np.pi)))

        if abs(last_row[-1] - row[-1]) < tolerance:
            break
        last_row = row
    return result


def romberg_scipy(f, start, end, show=False):
    return integrate.romberg(f, start, end, args=(), tol=1e-07, rtol=0, show=show)
